Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PP-13312 Settings for card types get controller #4376

Merged
merged 7 commits into from
Dec 10, 2024

Conversation

james-peacock-gds
Copy link
Contributor

@james-peacock-gds james-peacock-gds commented Dec 5, 2024

  • Get controller for simplified settings / card types
  • As design stipulates that admin users should see checkboxes and non-admins should see a simple list, implement two methods for formatting the card types data and two child templates to slot into the parent card types page.
  • Retain existing logic to disable checkbox for Maestro if the service doesn't have 3ds enabled.
  • Update existing logic to provide hint to enable with Worldpay for American Express and UnionPay - this is only necessary if it's a Worldpay service.

For subsequent PRs:

  • implement the post controller
  • Cypress tests

Screenshot for admin user
Screenshot 2024-12-05 at 13 04 39

Screenshot for non-admin user
Screenshot 2024-12-05 at 13 04 16

@james-peacock-gds james-peacock-gds force-pushed the PP-13312-Settings_card_types branch from efd06b5 to 3e8966c Compare December 5, 2024 12:53
@james-peacock-gds james-peacock-gds force-pushed the PP-13312-Settings_card_types branch from 25e1099 to 62a37a9 Compare December 5, 2024 13:02
Comment on lines 28 to 29
if (['American Express', 'Union Pay'].includes(cardTypeChecklistItem.text)) {
if (account.paymentProvider === 'worldpay') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be an if( A && B ) rather than nested if statements

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@james-peacock-gds james-peacock-gds marked this pull request as draft December 6, 2024 10:49
@james-peacock-gds james-peacock-gds marked this pull request as ready for review December 6, 2024 11:33
requires3ds: true
}
]
describe('format-card-types for template', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing for these hints in this test would be good too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point - this is now done.

return {
...cardTypeChecklistItem,
disabled: true,
hint: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are these hints shown in the UI? For example, when the mouse hovers over the label?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are always displayed as additional text underneath the card type if the conditions are met. The text under 'Maestro' in the first screenshot is an example of this.

oswaldquek
oswaldquek previously approved these changes Dec 6, 2024
@oswaldquek
Copy link
Contributor

Nice 1

@oswaldquek oswaldquek dismissed their stale review December 6, 2024 13:32

Use ControllerTestBuilder

Copy link
Collaborator

@nlsteers nlsteers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few 💬

})
}

const setupTest = (method, user, additionalReqProps = {}, additionalStubs = {}) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you refactor this test to use the new ControllerTestBuilder?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes!

@@ -257,6 +257,21 @@ ConnectorClient.prototype = {
return response.data
},

/**
* Retrieves the accepted card Types for the given account
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

service external id and account type is a more appropriate description to help differentiate from old gateway account based endpoints

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

const addHintForAmexAndUnionpayIfWorldpay = (cardTypeChecklistItem, paymentProvider) => {
if (['American Express', 'Union Pay'].includes(cardTypeChecklistItem.text) && paymentProvider === 'worldpay') {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should put these in an object somewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've declared the array at the top of the file

]
describe('format-card-types for template', () => {
describe('present checkboxes for admin user', () => {
it('should return all card types with checked boxes if they are all accepted', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can improve these tests, something like:

const expectedDebitCards = ['Visa debit', 'Mastercard debit', 'Maestro']
const expectedCreditCards = ['Visa credit', 'American Express', 'JCB']

expect(cards.debitCards).to.have.length(expectedDebitCards.length)
expect(cards.creditCards).to.have.length(expectedCreditCards.length)

cards.debitCards.forEach((card, idx) => {
  expect(card).to.deep.include({
    text: expectedDebitCards[idx],
    checked: true
  })
})

cards.creditCards.forEach((card, idx) => {
  expect(card).to.deep.include({
    text: expectedCreditCards[idx],
    checked: true
  })
})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree that using to.deep.include reduces repetition so I've updated this test and the next one. I'm not sure that using iterable brings a significant benefit with this small number of items and as far as I can see it isn't something that can be reused elsewhere in these tests. Happy to go with it though if you prefer.

@james-peacock-gds james-peacock-gds force-pushed the PP-13312-Settings_card_types branch from 25a26cd to 576877a Compare December 6, 2024 15:37
return { debitCards: debitCardChecklistItems, creditCards: creditCardChecklistItems }
}

const formatCardTypesForNonAdminTemplate = (allCards, acceptedCards) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the best I could come up with for refactoring this is something like this, but I'm not convinced it's an improvement so feel free to ignore it and stick with this implementation

Suggested change
const formatCardTypesForNonAdminTemplate = (allCards, acceptedCards) => {
const isDisabled = (card, account) => {
return card.requires3ds && !account.requires3ds
}
const hintText = (card, account) => {
const cardLabel = formatLabel(card)
const disabled = isDisabled(card, account)
if (disabled && account.type === 'test') {
return {
text: `${cardLabel} is not available on test accounts`
}
} else if (disabled) {
return {
text: `${cardLabel} cannot be used because 3D Secure is not available. Please contact support`
}
}
if (card.type !== 'CREDIT' || account.paymentProvider !== 'worldpay') {
return undefined
}
if (['American Express', 'Union Pay'].includes(cardLabel)) {
return {
html: 'You must have already enabled this with Worldpay'
}
}
return undefined
}
const formatCard = (card, accepted, account) => {
const disabled = isDisabled(card, account)
return {
value: card.id,
text: formatLabel(card),
checked: !disabled && accepted,
requires3ds: card.requires3ds,
disabled,
hint: hintText(card, account)
}
}
const formatCardTypesForNonAdminTemplate = (allCards, acceptedCards) => {
const items = allCards.reduce((acc, card) => {
if (!acc[card.type]) {
acc[card.type] = []
}
const accepted = acceptedCards.filter(c => c.type === card.type && c.id === card.id).length > 0
acc[card.type].push(formatCard(card, accepted, account))
return acc
}, {})
return {
debitCards: Object.values(items.DEBIT),
creditCards: Object.values(items.CREDIT)
}
}

Comment on lines +58 to +69
const formattedCardTypes = {
'Enabled debit cards': [],
'Not enabled debit cards': [],
'Enabled credit cards': [],
'Not enabled credit cards': []
}
allCards.forEach(card => {
const cardIsEnabled = acceptedCardTypeIds.includes(card.id) ? 'Enabled' : 'Not enabled'
formattedCardTypes[`${cardIsEnabled} ${card.type.toLowerCase()} cards`].push(formatLabel(card))
})
return formattedCardTypes
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a slight change I might suggest would be something like

Suggested change
const formattedCardTypes = {
'Enabled debit cards': [],
'Not enabled debit cards': [],
'Enabled credit cards': [],
'Not enabled credit cards': []
}
allCards.forEach(card => {
const cardIsEnabled = acceptedCardTypeIds.includes(card.id) ? 'Enabled' : 'Not enabled'
formattedCardTypes[`${cardIsEnabled} ${card.type.toLowerCase()} cards`].push(formatLabel(card))
})
return formattedCardTypes
}
const formattedCardTypes = {
'debit/enabled': {
cards: [],
heading: 'Enabled debit cards'
}
...
}
allCards.forEach(card => {
const cardIsEnabled = acceptedCardTypeIds.includes(card.id) ? 'enabled' : 'disabled'
formattedCardTypes[`${card.type.toLowerCase()}/${cardIsEnabled}`].push(formatLabel(card))
})

just so the heading isn't the object key

@james-peacock-gds james-peacock-gds merged commit a8e47a0 into master Dec 10, 2024
14 checks passed
@james-peacock-gds james-peacock-gds deleted the PP-13312-Settings_card_types branch December 10, 2024 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants